import matplotlib.pyplot as plt
import matplotlib.animation as animation
import subprocess
import re
import os
import argparse

def get_dynamic_ram(log_path):
	try:
		if not os.path.isfile(log_path):
			raise FileNotFoundError(f"Log file '{log_path}' not found.")

		output = subprocess.run(["tail", "-n", "6", log_path], capture_output=True, text=True, check=True)
	except FileNotFoundError as e:
		print(e)
		return []
	except subprocess.CalledProcessError as e:
		print(f"Failed to load the log file: {e}")
		return []

	lines = output.stdout.strip().split("\n")
	dynamic_ram_values = []

	for line in lines:
		match = re.search(r"dynamic_ram:(\d+)", line)
		if match:
			ram_value = int(match.group(1)) / 1024
			dynamic_ram_values.append(round(ram_value, 2))

	return dynamic_ram_values

def get_static_ram(output_path):
	if not os.path.isdir(output_path):
		return []

	try:
		find_process = subprocess.run(["find", output_path, "-name", "*.obj"], capture_output=True, text=True, check=True)
		object_files = find_process.stdout.splitlines()
		if not object_files:
			return []

		calc_process = subprocess.run(
			['xargs', 'python3', 'vbslite_calc_static_ram.py', '-p', 'linux'],
			input='\n'.join(object_files),
			capture_output=True,
			text=True,
			check=True
		)

		static_ram_module_values = []
		for line in calc_process.stdout.splitlines():
			match = re.search(r"Total Size of RAM: (\d+) bytes", line)
			if match:
				static_ram_module_values.append(round(int(match.group(1)) / 1024, 1))

		return static_ram_module_values
	except subprocess.CalledProcessError:
		return []

def get_mvbs_all_static_ram():
	paths = {
		"stack": "../../../output/apps/vcos_examples/vbslite_demo/vbslite_node1/apps/CMakeFiles/apps_mvbs_demo.dir/home",
		"idl": "../../../output/apps/vcos_examples/vbslite_demo/vbslite_node1/apps/CMakeFiles/apps_mvbs_demo.dir/gen/idl",
		"xml": "../../../output/apps/vcos_examples/vbslite_demo/vbslite_node1/apps/CMakeFiles/apps_mvbs_demo.dir/gen/xml"
	}

	missing_paths = []
	static_ram_values = []

	for name, path in paths.items():
		if not os.path.isdir(path):
			missing_paths.append(name)
		else:
			static_ram_values.extend(get_static_ram(path))

	if missing_paths:
		print(f"Missing paths: {', '.join(missing_paths)}. Skipping static RAM calculation for these parts.")

	return static_ram_values

def animate(i, log_path):
	global x_data, dynamic_ram_data, static_ram_data

	dynamic_ram_values = get_dynamic_ram(log_path)
	static_ram_values = get_mvbs_all_static_ram()

	if dynamic_ram_values:
		x_data.append(i)
		dynamic_ram_data.append(dynamic_ram_values[-1])
		static_ram_data.append(static_ram_values[-1] if static_ram_values else None)

	ax.clear()

	# 处理静态RAM
	valid_static_indices = [idx for idx, val in enumerate(static_ram_data) if val is not None]
	if valid_static_indices:
		valid_x = [x_data[idx] for idx in valid_static_indices]
		valid_y = [static_ram_data[idx] for idx in valid_static_indices]
		ax.plot(valid_x, valid_y, color='red', linewidth=2,
				label=f'Static RAM = {valid_y[-1]}Kb', zorder=3)
	else:
		ax.axhline(93.8, color='red', linestyle='--', linewidth=2,
				  label='Static RAM = 93.8Kb', zorder=2)

	# 绘制动态RAM
	if x_data and dynamic_ram_data:
		ax.plot(x_data, dynamic_ram_data, color='blue', linewidth=2,
				label=f'Dynamic RAM = {dynamic_ram_data[-1]}Kb', zorder=3)



	# 统一设置图形属性
	ax.set_title("VBSLite RAM Memory Usage Results (300Topics)",
				fontsize=14, pad=10, fontweight='bold')
	ax.set_ylabel("RAM Usage(kb)")
	ax.set_xlabel("Time (seconds)")

	# 动态调整坐标轴范围
	current_max = max([*dynamic_ram_data, *[v for v in static_ram_data if v]], default=100)
	ax.set_xlim(left=0, right=(i+10) if x_data else 10)
	ax.set_ylim(bottom=-50, top=max(current_max+100, 150))  # 确保默认线可见

	ax.spines[['top', 'right']].set_visible(False)
	ax.legend(loc='upper right', frameon=True, framealpha=0.95, edgecolor='#333333')

def main():
	global ax, x_data, dynamic_ram_data, static_ram_data

	parser = argparse.ArgumentParser(description='Process log file for RAM usage.')
	parser.add_argument('-f', '--file', required=True, help='Path to the log file')
	args = parser.parse_args()

	x_data, dynamic_ram_data, static_ram_data = [], [], []
	fig, ax = plt.subplots(figsize=(10, 6))
	plt.tight_layout()
	plt.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)

	ani = animation.FuncAnimation(fig, animate, fargs=(args.file,), interval=500, cache_frame_data=False)
	plt.show()

if __name__ == "__main__":
	main()